package cn.gs.global.server.meta;

// @author gs
import cn.gs.global.table.meta.Obj;
import cn.gs.util.set.Cache;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class ChangeCalUtil {

    private Obj[] objs;
    private double[][] value;
    static Cache<Integer, ChangeCalUtil> cache = new Cache<>(100, 30 * 60 * 1000); //half hour

    private ChangeCalUtil(Obj[] objs, double[][] value) {
        this.objs = objs;
        this.value = value;
    }

    public static void remove(Obj obj) {
        cache.remove(obj.getId());
    }

    public static ChangeCalUtil calOneChg(Obj obj) {
        ChangeCalUtil chg = null;
        if ((chg = cache.get(obj.getId())) == null) {
            List<Obj> folTopSorted = obj.folTopSort();
            if (folTopSorted == null) {
                return null;
            }
            assert folTopSorted.contains(obj);
            Obj[] objs = new Obj[folTopSorted.size()];
            double[][] value = new double[folTopSorted.size()][6];
            folTopSorted.toArray(objs);
            //Calc, assume num = 1
            Map<Obj, Integer> indexes = new HashMap<>();
            for (int i = 0; i < objs.length; ++i) {
                indexes.put(objs[i], i);
            }
            value[indexes.get(obj)][0] = 1;
            for (int i = 0; i < 6; ++i) {
                for (int j = 0; j < objs.length; ++j) {
                    for (Entry<Obj, Double> e : objs[j].getFol().entrySet()) {
                        int z = indexes.get(e.getKey());
                        value[z][i] += value[j][i] * e.getValue();
                    }
                }
                if (i < 5) {
                    for (int j = 0; j < objs.length; ++j) {
                        for (Entry<Obj, Double> e : objs[j].getChg().entrySet()) {
                            int z = indexes.get(e.getKey());
                            value[z][i + 1] += value[j][i] * e.getValue();
                        }
                    }
                }
            }
            chg = new ChangeCalUtil(objs, value);
            cache.put(obj.getId(), chg);
        }
        return chg;
    }

    public Obj[] getObjs() {
        return objs;
    }

    public double[][] getValue() {
        return value;
    }
}
